import re
import os
import time
import tkinter as tk
from datetime import datetime
from tkinter import filedialog, messagebox, ttk, Toplevel
import json
import jieba
import numpy as np    
from PyPDF2 import PdfReader
from docx import Document
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.utils.extmath import randomized_svd
import requests
from bs4 import BeautifulSoup
import traceback
from tkinter import font as tkfont
from PIL import Image, ImageTk

class HistoryWindow:
    def __init__(self, parent):
        self.parent = parent
        self.window = tk.Toplevel(parent)
        self.window.title('历史记录')
        self.window.geometry('1000x700')
        self.window.configure(bg='#f0f2f5')
        self.window.transient(parent)  # 设置为父窗口的临时窗口
        
        # 创建主框架
        main_frame = ttk.Frame(self.window, style='Main.TFrame')
        main_frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 创建标题标签
        title_frame = ttk.Frame(main_frame, style='Title.TFrame')
        title_frame.pack(fill='x', pady=(0, 15))
        
        title_label = ttk.Label(
            title_frame, 
            text='操作历史记录', 
            style='Title.TLabel'
        )
        title_label.pack(pady=5)
        
        # 创建内容框架
        content_frame = ttk.Frame(main_frame, style='Content.TFrame')
        content_frame.pack(fill='both', expand=True, pady=5)
        
        # 历史记录列表框架
        list_frame = ttk.LabelFrame(
            content_frame, 
            text='历史操作记录', 
            style='Card.TLabelframe'
        )
        list_frame.pack(fill='both', expand=True, pady=(0, 10))
        
        # 创建历史记录表格
        columns = ('timestamp', 'operation', 'preview')
        self.tree = ttk.Treeview(
            list_frame, 
            columns=columns, 
            show='headings', 
            height=15,
            selectmode='browse'
        )
        
        # 定义列
        self.tree.heading('timestamp', text='时间')
        self.tree.heading('operation', text='操作类型')
        self.tree.heading('preview', text='内容预览')
        
        self.tree.column('timestamp', width=180, anchor='w')
        self.tree.column('operation', width=120, anchor='center')
        self.tree.column('preview', width=600, anchor='w')
        
        # 添加滚动条
        tree_scroll = ttk.Scrollbar(list_frame, command=self.tree.yview)
        self.tree.configure(yscrollcommand=tree_scroll.set)
        
        # 绑定双击事件
        self.tree.bind('<Double-1>', lambda e: self.view_details())
        
        # 布局
        self.tree.pack(side='left', fill='both', expand=True, padx=(10, 0), pady=10)
        tree_scroll.pack(side='right', fill='y', padx=(0, 10), pady=10)
        
        # 详情显示区域
        detail_frame = ttk.LabelFrame(
            content_frame, 
            text='详细信息', 
            style='Card.TLabelframe'
        )
        detail_frame.pack(fill='x', pady=(0, 10), ipady=5)
        
        # 创建选项卡
        self.notebook = ttk.Notebook(detail_frame)
        self.notebook.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 原文选项卡
        self.original_frame = ttk.Frame(self.notebook)
        self.original_text = tk.Text(
            self.original_frame, 
            wrap=tk.WORD,
            height=8,
            font=('微软雅黑', 11),
            bg='#ffffff',
            fg='#333333',
            padx=12,
            pady=12,
            relief='flat'
        )
        orig_scroll = ttk.Scrollbar(self.original_frame, command=self.original_text.yview)
        self.original_text.configure(yscrollcommand=orig_scroll.set)
        self.original_text.pack(side='left', fill='both', expand=True)
        orig_scroll.pack(side='right', fill='y')
        
        # 结果选项卡
        self.result_frame = ttk.Frame(self.notebook)
        self.result_text = tk.Text(
            self.result_frame, 
            wrap=tk.WORD,
            height=8,
            font=('微软雅黑', 11),
            bg='#ffffff',
            fg='#333333',
            padx=12,
            pady=12,
            relief='flat'
        )
        result_scroll = ttk.Scrollbar(self.result_frame, command=self.result_text.yview)
        self.result_text.configure(yscrollcommand=result_scroll.set)
        self.result_text.pack(side='left', fill='both', expand=True)
        result_scroll.pack(side='right', fill='y')
        
        # 添加选项卡
        self.notebook.add(self.original_frame, text='原文内容')
        self.notebook.add(self.result_frame, text='处理结果')
        
        # 操作按钮
        btn_frame = ttk.Frame(main_frame)
        btn_frame.pack(pady=10)
        
        self.view_btn = ttk.Button(
            btn_frame, 
            text='查看详情',
            style='Accent.TButton', 
            command=self.view_details
        )
        self.view_btn.pack(side='left', padx=5)
        
        self.delete_btn = ttk.Button(
            btn_frame, 
            text='删除记录',
            style='Upload.TButton', 
            command=self.delete_record
        )
        self.delete_btn.pack(side='left', padx=5)
        
        self.clear_btn = ttk.Button(
            btn_frame, 
            text='清空历史',
            style='Upload.TButton', 
            command=self.clear_history
        )
        self.clear_btn.pack(side='left', padx=5)
        
        self.close_btn = ttk.Button(
            btn_frame, 
            text='关闭', 
            command=self.window.destroy
        )
        self.close_btn.pack(side='left', padx=5)
        
        # 初始化
        self.history_file = 'history.json'
        self.load_history()
        
        # 初始化详情区域
        self.update_detail(None)

    def load_history(self):
        """加载历史记录"""
        try:
            if not os.path.exists(self.history_file):
                with open(self.history_file, 'w', encoding='utf-8') as f:
                    f.write('[]')
                return
                
            with open(self.history_file, 'r', encoding='utf-8') as f:
                history = json.load(f)
                
                # 按时间排序
                sorted_history = sorted(
                    history, 
                    key=lambda x: x.get('time', datetime.strptime(x.get('timestamp', '1970-01-01 00:00:00'), '%Y-%m-%d %H:%M:%S').timestamp()), 
                    reverse=True
                )
                
                # 清空现有数据
                for item in self.tree.get_children():
                    self.tree.delete(item)
                    
                # 填充数据
                for item in sorted_history:
                    # 获取预览文本(去除换行符)
                    preview = item.get('original', '')[:100].replace('\n', ' ') + '...'
                    
                    # 插入记录
                    self.tree.insert(
                        '', 
                        'end', 
                        values=(item.get('timestamp', ''), item.get('operation', '未知操作'), preview),
                        tags=(item.get('timestamp', ''))
                    )
                
                # 如果有记录，选中第一条
                children = self.tree.get_children()
                if children:
                    self.tree.selection_set(children[0])
                    self.tree.focus(children[0])
                    self.view_details()
                    
        except (FileNotFoundError, json.JSONDecodeError) as e:
            # 如果文件不存在或格式错误，创建空文件
            with open(self.history_file, 'w', encoding='utf-8') as f:
                f.write('[]')
            
            # 在UI中显示错误信息
            self.update_detail(None, error=str(e))
    
    def update_detail(self, record, error=None):
        """更新详情区域"""
        # 清空文本框
        self.original_text.config(state='normal')
        self.original_text.delete(1.0, tk.END)
        self.result_text.config(state='normal')
        self.result_text.delete(1.0, tk.END)
        
        if error:
            self.original_text.insert(tk.END, f"加载错误: {error}")
            self.result_text.insert(tk.END, "无法加载数据")
        elif record:
            # 填充原文内容
            self.original_text.insert(tk.END, record.get('original', '无原文内容'))
            
            # 填充处理结果，并更新选项卡标题
            result = record.get('result', '')
            if result:
                self.result_text.insert(tk.END, result)
                self.notebook.tab(1, text=f"{record.get('operation', '处理')}结果")
            else:
                self.result_text.insert(tk.END, "无处理结果")
                self.notebook.tab(1, text='处理结果')
        else:
            self.original_text.insert(tk.END, "请选择一条历史记录")
            self.result_text.insert(tk.END, "请选择一条历史记录")
        
        # 设为只读
        self.original_text.config(state='disabled')
        self.result_text.config(state='disabled')

    def view_details(self):
        """查看记录详情"""
        selected = self.tree.selection()
        if not selected:
            self.update_detail(None)
            return
            
        item_id = selected[0]
        values = self.tree.item(item_id, 'values')
        
        if not values or len(values) < 3:
            self.update_detail(None)
            return
            
        timestamp = values[0]
        operation = values[1]
        
        try:
            with open(self.history_file, 'r', encoding='utf-8') as f:
                history = json.load(f)
                
                # 查找匹配的记录
                for record in history:
                    if record.get('timestamp') == timestamp and record.get('operation') == operation:
                        self.update_detail(record)
                        return
                        
                # 如果没找到匹配记录
                self.update_detail(None)
                
        except (FileNotFoundError, json.JSONDecodeError):
            self.update_detail(None, error="历史记录文件不存在或已损坏")

    def delete_record(self):
        """删除选中的记录"""
        selected = self.tree.selection()
        if not selected:
            messagebox.showinfo('提示', '请先选择要删除的记录')
            return
            
        if not messagebox.askyesno('确认', '确定要删除选中的记录吗？'):
            return
            
        item_id = selected[0]
        values = self.tree.item(item_id, 'values')
        
        if not values or len(values) < 2:
            return
            
        timestamp = values[0]
        operation = values[1]
        
        try:
            with open(self.history_file, 'r', encoding='utf-8') as f:
                    history = json.load(f)
                
            # 过滤掉要删除的记录
            new_history = [
                record for record in history 
                if not (record.get('timestamp') == timestamp and record.get('operation') == operation)
            ]
            
            # 写回文件
            with open(self.history_file, 'w', encoding='utf-8') as f:
                json.dump(new_history, f, ensure_ascii=False, indent=2)
                
            # 从树中删除
            self.tree.delete(item_id)
            
            # 更新详情区域
            self.update_detail(None)
            
            messagebox.showinfo('成功', '记录已删除')
            
        except Exception as e:
            messagebox.showerror('错误', f'删除记录失败: {str(e)}')

    def clear_history(self):
        """清空所有历史记录"""
        if not messagebox.askyesno('确认', '确定要清空所有历史记录吗？此操作不可恢复！'):
            return
            
        try:
            # 清空文件
            with open(self.history_file, 'w', encoding='utf-8') as f:
                f.write('[]')
                
            # 清空树视图
            for item in self.tree.get_children():
                self.tree.delete(item)
                
            # 更新详情区域
            self.update_detail(None)
            
            messagebox.showinfo('成功', '所有历史记录已清空')
            
        except Exception as e:
            messagebox.showerror('错误', f'清空历史记录失败: {str(e)}')

class MainWindow(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title('新闻文档摘要系统')
        self.geometry('1000x700')
        self.configure(bg='#f0f2f5')
        
        # 应用自定义样式
        self.apply_modern_style()
        
        # 创建主框架
        self.main_frame = ttk.Frame(self, style='Main.TFrame')
        self.main_frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 创建标题标签
        title_frame = ttk.Frame(self.main_frame, style='Title.TFrame')
        title_frame.pack(fill='x', pady=(0, 20))
        
        title_label = ttk.Label(
            title_frame, 
            text='新闻文档摘要系统', 
            style='Title.TLabel'
        )
        title_label.pack(pady=10)
        
        subtitle_label = ttk.Label(
            title_frame, 
            text='基于潜在语义分析的新闻文档智能摘要生成',
            style='Subtitle.TLabel'
        )
        subtitle_label.pack(pady=(0, 10))
        
        # 创建内容框架
        content_frame = ttk.Frame(self.main_frame, style='Content.TFrame')
        content_frame.pack(fill='both', expand=True, pady=10)
        
        # 左侧输入区域
        input_frame = ttk.LabelFrame(
            content_frame, 
            text='文档输入', 
            style='Card.TLabelframe'
        )
        input_frame.pack(side='left', fill='both', expand=True, padx=(0, 10))
        
        # URL输入区域
        url_frame = ttk.Frame(input_frame)
        url_frame.pack(fill='x', padx=10, pady=(15, 5))
        
        url_label = ttk.Label(url_frame, text='网页URL:', style='Input.TLabel')
        url_label.pack(side='left', padx=(0, 10))
        
        self.url_entry = ttk.Entry(url_frame, width=50, style='Modern.TEntry')
        self.url_entry.pack(side='left', fill='x', expand=True, padx=(0, 10))
        
        self.crawl_btn = ttk.Button(
            url_frame, 
            text='爬取网页', 
            style='Accent.TButton',
            command=self.crawl_webpage
        )
        self.crawl_btn.pack(side='right')
        
        # 文本输入区域
        text_frame = ttk.Frame(input_frame)
        text_frame.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 添加上传按钮区域
        upload_frame = ttk.Frame(text_frame)
        upload_frame.pack(fill='x', pady=(0, 10))
        
        # 上传文件按钮
        self.upload_btn = ttk.Button(
            upload_frame, 
            text='上传文件', 
            style='Upload.TButton',
            command=self.upload_file
        )
        self.upload_btn.pack(side='left', padx=5)
        
        # 文件类型选择
        file_type_frame = ttk.Frame(upload_frame)
        file_type_frame.pack(side='left', padx=20)
        
        ttk.Label(file_type_frame, text='文件类型:').pack(side='left')
        
        self.file_type_var = tk.StringVar(value='txt')
        ttk.Radiobutton(
            file_type_frame, 
            text='TXT', 
            variable=self.file_type_var, 
            value='txt'
        ).pack(side='left', padx=5)
        
        ttk.Radiobutton(
            file_type_frame, 
            text='PDF', 
            variable=self.file_type_var, 
            value='pdf'
        ).pack(side='left', padx=5)
        
        ttk.Radiobutton(
            file_type_frame, 
            text='DOCX', 
            variable=self.file_type_var, 
            value='docx'
        ).pack(side='left', padx=5)
        
        # 文本输入框和滚动条
        self.text_input = tk.Text(
            text_frame, 
            wrap=tk.WORD, 
            font=('微软雅黑', 11),
            bg='#ffffff',
            fg='#333333',
            insertbackground='#007bff',
            relief='flat',
            padx=12,
            pady=12
        )
        self.text_input.pack(side='left', fill='both', expand=True)
        
        text_scrollbar = ttk.Scrollbar(text_frame, command=self.text_input.yview)
        text_scrollbar.pack(side='right', fill='y')
        self.text_input.configure(yscrollcommand=text_scrollbar.set)
        
        # 右侧功能区域
        func_frame = ttk.Frame(content_frame, style='Content.TFrame')
        func_frame.pack(side='right', fill='both')
        
        # 功能卡片
        tools_frame = ttk.LabelFrame(
            func_frame, 
            text='功能工具', 
            style='Card.TLabelframe'
        )
        tools_frame.pack(fill='both', padx=(0, 0), pady=(0, 10))
        
        # 功能按钮
        self.tokenize_btn = ttk.Button(
            tools_frame, 
            text='分词处理', 
            style='Function.TButton',
            command=self.show_tokenization
        )
        self.tokenize_btn.pack(fill='x', padx=20, pady=(20, 10))
        
        self.weight_btn = ttk.Button(
            tools_frame, 
            text='权重计算', 
            style='Function.TButton',
            command=self.show_weight_calculation
        )
        self.weight_btn.pack(fill='x', padx=20, pady=10)
        
        self.summary_btn = ttk.Button(
            tools_frame, 
            text='生成摘要', 
            style='Function.TButton',
            command=self.show_summary_generation
        )
        self.summary_btn.pack(fill='x', padx=20, pady=10)
        
        self.history_btn = ttk.Button(
            tools_frame, 
            text='历史记录', 
            style='Function.TButton',
            command=self.show_history
        )
        self.history_btn.pack(fill='x', padx=20, pady=(10, 20))
        
        # 状态信息卡片
        status_frame = ttk.LabelFrame(
            func_frame, 
            text='状态信息', 
            style='Card.TLabelframe'
        )
        status_frame.pack(fill='both', expand=True)
        
        self.status_text = tk.Text(
            status_frame, 
            height=8, 
            wrap=tk.WORD, 
            font=('微软雅黑', 10),
            bg='#f8f9fa',
            fg='#6c757d',
            relief='flat',
            state='disabled'
        )
        self.status_text.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 底部信息栏
        footer_frame = ttk.Frame(self.main_frame, style='Footer.TFrame')
        footer_frame.pack(fill='x', pady=(20, 0))
        
        footer_label = ttk.Label(
            footer_frame, 
            text='基于潜在语义分析的新闻文档摘要生成系统 © ' + str(datetime.now().year),
            style='Footer.TLabel'
        )
        footer_label.pack(side='right')
        
        # 初始化历史记录
        self.history_file = 'history.json'
        
        # 更新状态信息
        self.update_status("系统已就绪，请输入文本或上传文件...")
    
    def apply_modern_style(self):
        """应用现代化样式"""
        self.style = ttk.Style()
        
        # 可用主题: 'clam', 'alt', 'default', 'classic'
        self.style.theme_use('clam')
        
        # 定义颜色
        primary_color = '#007bff'
        secondary_color = '#6c757d'
        success_color = '#28a745'
        info_color = '#17a2b8'
        warning_color = '#ffc107'
        danger_color = '#dc3545'
        light_color = '#f8f9fa'
        dark_color = '#343a40'
        
        # 框架样式
        self.style.configure('Main.TFrame', background='#f0f2f5')
        self.style.configure('Title.TFrame', background='#f0f2f5')
        self.style.configure('Content.TFrame', background='#f0f2f5')
        self.style.configure('Footer.TFrame', background='#f0f2f5')
        
        # 标签样式
        self.style.configure(
            'Title.TLabel',
            font=('微软雅黑', 24, 'bold'),
            foreground=dark_color,
            background='#f0f2f5'
        )
        self.style.configure(
            'Subtitle.TLabel',
            font=('微软雅黑', 12),
            foreground=secondary_color,
            background='#f0f2f5'
        )
        self.style.configure(
            'Input.TLabel',
            font=('微软雅黑', 11),
            background='#ffffff'
        )
        self.style.configure(
            'Footer.TLabel',
            font=('微软雅黑', 9),
            foreground=secondary_color,
            background='#f0f2f5'
        )
        
        # 卡片样式
        self.style.configure(
            'Card.TLabelframe',
            font=('微软雅黑', 12, 'bold'),
            background='#ffffff',
            borderwidth=1,
            relief='solid'
        )
        self.style.configure(
            'Card.TLabelframe.Label',
            font=('微软雅黑', 12, 'bold'),
            foreground=dark_color,
            background='#ffffff'
        )
        
        # 按钮样式
        self.style.configure(
            'Accent.TButton',
            font=('微软雅黑', 10),
            background=primary_color,
            foreground='white',
            padding=6
        )
        self.style.map(
            'Accent.TButton',
            background=[('active', '#0069d9'), ('disabled', '#6c757d')]
        )
        
        self.style.configure(
            'Upload.TButton',
            font=('微软雅黑', 10),
            background=info_color,
            foreground='white',
            padding=6
        )
        self.style.map(
            'Upload.TButton',
            background=[('active', '#138496'), ('disabled', '#6c757d')]
        )
        
        self.style.configure(
            'Function.TButton',
            font=('微软雅黑', 12),
            background='#ffffff',
            foreground=dark_color,
            padding=12
        )
        self.style.map(
            'Function.TButton',
            background=[('active', light_color), ('pressed', light_color)],
            foreground=[('active', primary_color)]
        )
        
        # 输入框样式
        self.style.configure(
            'Modern.TEntry',
            fieldbackground='#ffffff',
            foreground=dark_color,
            insertcolor=primary_color
        )
        
        # 设置滚动条样式
        self.style.configure(
            'TScrollbar',
            troughcolor=light_color,
            background=secondary_color,
            arrowcolor='white',
            borderwidth=0,
            arrowsize=13
        )
        self.style.map(
            'TScrollbar',
            background=[('active', primary_color), ('!active', '#adb5bd')]
        )
    
    def update_status(self, message):
        """更新状态信息"""
        self.status_text.config(state='normal')
        self.status_text.delete(1.0, tk.END)
        timestamp = datetime.now().strftime("%H:%M:%S")
        self.status_text.insert(tk.END, f"[{timestamp}] {message}")
        self.status_text.config(state='disabled')
        self.update_idletasks()

    def crawl_webpage(self):
        """爬取网页内容"""
        self.update_status("正在爬取网页内容...")
        try:
            url = self.url_entry.get().strip()
            if not url:
                messagebox.showwarning('提示', '请输入网页URL')
                return
                
            if not url.startswith(('http://', 'https://')):
                url = 'http://' + url
            
            response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'}, timeout=10)
            
            # 自动检测编码
            if response.encoding != 'utf-8':
                detected_encoding = response.apparent_encoding
                try:
                    response.encoding = detected_encoding if detected_encoding else 'utf-8'
                except:
                    response.encoding = 'utf-8'
            
            # 使用正确编码重新解码内容
            decoded_content = response.content.decode(response.encoding, errors='replace')
            soup = BeautifulSoup(decoded_content, 'html.parser')
            
            # 移除脚本和样式
            for script in soup(['script', 'style', 'nav', 'footer', 'header']):
                script.decompose()
                
            text = '\n'.join(p.get_text().strip() for p in soup.find_all('p') if p.get_text().strip())
            
            if not text:
                messagebox.showwarning('提示', '未能提取到有效文本内容')
                self.update_status("网页爬取完成，但未提取到内容")
                return
                
            self.text_input.delete(1.0, tk.END)
            self.text_input.insert(tk.END, text)
            self.save_history('网页爬取', url, text[:500] + '...')
            self.update_status(f"网页爬取成功，已提取{len(text)}个字符")
        except ImportError as e:
            messagebox.showerror('依赖缺失', f'请先安装所需依赖库: {e.name}\n使用命令: pip install -r requirements.txt')
            self.update_status(f"爬取失败: 缺少依赖 {e.name}")
        except Exception as e:
            messagebox.showerror('错误', f'网页抓取失败: {str(e)}')
            self.update_status(f"爬取失败: {str(e)}")
    
    def upload_file(self):
        """上传并解析文件"""
        self.update_status("正在选择文件...")
        file_type = self.file_type_var.get()
        
        # 根据选择的文件类型设置文件过滤器
        if file_type == 'txt':
            filetypes = [('文本文件', '*.txt'), ('所有文件', '*.*')]
        elif file_type == 'pdf':
            filetypes = [('PDF文件', '*.pdf'), ('所有文件', '*.*')]
        elif file_type == 'docx':
            filetypes = [('Word文档', '*.docx'), ('所有文件', '*.*')]
        else:
            filetypes = [
                ('所有支持的文件', '*.txt *.pdf *.docx'),
                ('文本文件', '*.txt'),
                ('PDF文件', '*.pdf'),
                ('Word文档', '*.docx'),
                ('所有文件', '*.*')
            ]
        
        filepath = filedialog.askopenfilename(filetypes=filetypes)
        if filepath:
            self.update_status(f"正在解析文件: {os.path.basename(filepath)}...")
            try:
                content = self.parse_file(filepath)
                if content:
                    self.text_input.delete(1.0, tk.END)
                    self.text_input.insert(tk.END, content)
                    self.update_status(f"文件加载成功: {os.path.basename(filepath)}")
                    self.save_history('文件加载', filepath, content[:500] + '...')
                else:
                    self.update_status("文件解析失败：内容为空")
            except Exception as e:
                error_msg = f"文件解析失败: {str(e)}"
                messagebox.showerror('错误', error_msg)
                self.update_status(error_msg)
    
    def parse_file(self, filepath):
        """解析不同类型的文件"""
        try:
            if filepath.endswith('.pdf'):
                return self.parse_pdf(filepath)
            elif filepath.endswith('.docx'):
                return self.parse_docx(filepath)
            else:
                # 尝试不同编码打开文本文件
                encodings = ['utf-8', 'gbk', 'gb2312', 'iso-8859-1']
                for encoding in encodings:
                    try:
                        with open(filepath, 'r', encoding=encoding) as f:
                            return f.read()
                    except UnicodeDecodeError:
                        continue
                
                # 如果所有编码都失败，使用二进制模式
                with open(filepath, 'rb') as f:
                    content = f.read()
                    return content.decode('utf-8', errors='replace')
        except Exception as e:
            messagebox.showerror('错误', f'文件解析失败: {str(e)}')
            self.update_status(f"文件解析失败: {str(e)}")
            return ''

    def parse_pdf(self, filepath):
        """解析PDF文件"""
        text = ''
        try:
            with open(filepath, 'rb') as f:
                reader = PdfReader(f)
                for page in reader.pages:
                    text += page.extract_text() + '\n'
            return text
        except Exception as e:
            messagebox.showerror('错误', f'PDF解析失败: {str(e)}')
            return ''

    def parse_docx(self, filepath):
        """解析DOCX文件"""
        try:
            doc = Document(filepath)
            return '\n'.join([para.text for para in doc.paragraphs])
        except Exception as e:
            messagebox.showerror('错误', f'Word文档解析失败: {str(e)}')
            return ''
    
    def show_tokenization(self):
        """显示分词处理窗口"""
        content = self.text_input.get(1.0, tk.END).strip()
        if not content:
            messagebox.showwarning('提示', '请先输入或上传文档内容')
            return
        
        self.update_status("正在进行分词处理...")
        TokenizationWindow(self, content)
    
    def show_weight_calculation(self):
        """显示权重计算窗口"""
        content = self.text_input.get(1.0, tk.END).strip()
        if not content:
            messagebox.showwarning('提示', '请先输入或上传文档内容')
            return
        
        self.update_status("正在进行权重计算...")
        WeightCalculationWindow(self, content)

    def show_summary_generation(self):
        """显示摘要生成窗口"""
        content = self.text_input.get(1.0, tk.END).strip()
        if not content:
            messagebox.showwarning('提示', '请先输入或上传文档内容')
            return
        
        self.update_status("正在生成文档摘要...")
        summary_win = SummaryWindow(self, content)
        
        # 等待摘要窗口关闭后保存历史记录
        self.wait_window(summary_win.window)
        if hasattr(summary_win, 'summary'):
            self.save_history('生成摘要', content, summary_win.summary)
            self.update_status("摘要生成完成")

    def show_history(self):
        """显示历史记录窗口"""
        self.update_status("正在加载历史记录...")
        try:
            if not os.path.exists(self.history_file):
                with open(self.history_file, 'w', encoding='utf-8') as f:
                    f.write('[]')
                    
            with open(self.history_file, 'r', encoding='utf-8') as f:
                history = json.load(f)
                
            HistoryWindow(self)
            self.update_status("历史记录加载完成")
        except FileNotFoundError:
            messagebox.showinfo('提示', '暂无历史记录')
            self.update_status("未找到历史记录文件")
        except json.JSONDecodeError:
            messagebox.showinfo('提示', '历史记录文件损坏，已重置')
            with open(self.history_file, 'w', encoding='utf-8') as f:
                f.write('[]')
            self.update_status("历史记录文件已重置")
        except Exception as e:
            messagebox.showerror('错误', f'读取历史记录失败: {str(e)}')
            self.update_status(f"读取历史记录失败: {str(e)}")

    def save_history(self, operation, content, result):
        """
        保存历史记录
        :param operation: 操作类型（分词处理/权重计算/生成摘要）
        :param content: 操作内容
        :param result: 操作结果
        """
        record = {
            'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'),
            'time': datetime.now().timestamp(),  # 用于排序
            'operation': operation if operation else '未知操作',
            'original': content[:5000] + '...' if len(content) > 5000 else content,
            'result': result[:5000] + '...' if len(result) > 5000 else result
        }
        try:
            history = []
            if os.path.exists(self.history_file):
                with open(self.history_file, 'r', encoding='utf-8') as f:
                    try:
                        history = json.load(f)
                    except json.JSONDecodeError:
                        history = []
            history.append(record)
            with open(self.history_file, 'w', encoding='utf-8') as f:
                json.dump(history, f, ensure_ascii=False, indent=2)
        except Exception as e:
            messagebox.showerror('错误', f'保存历史记录失败: {str(e)}')
            # 打印错误日志以便调试
            print(f'History save error: {e}')
            traceback.print_exc()
        
    # 添加关键词提取功能
    def extract_keywords(self):
        """提取文本关键词"""
        content = self.text_input.get(1.0, tk.END).strip()
        if not content:
            messagebox.showwarning('提示', '请先输入或上传文档内容')
            return
        
        self.update_status("正在提取关键词...")
        try:
            # 使用TF-IDF提取关键词
            words = ' '.join(jieba.cut(content))
            sentences = [words]
            vectorizer = TfidfVectorizer(max_features=15)
            tfidf_matrix = vectorizer.fit_transform(sentences)
            feature_names = vectorizer.get_feature_names_out()
            
            # 获取关键词及其权重
            features = []
            for col in range(tfidf_matrix.shape[1]):
                features.append((feature_names[col], tfidf_matrix[0, col]))
            
            # 按分数降序排序
            sorted_features = sorted(features, key=lambda x: x[1], reverse=True)
            
            # 格式化显示
            result = "文档关键词 (TF-IDF):\n\n"
            for word, score in sorted_features[:10]:
                result += f"{word}: {score:.4f}\n"
            
            # 显示结果
            messagebox.showinfo('关键词提取结果', result)
            self.update_status("关键词提取完成")
            
            # 保存到历史记录
            self.save_history('关键词提取', content, result)
            
        except Exception as e:
            messagebox.showerror('错误', f'关键词提取失败: {str(e)}')
            self.update_status(f"关键词提取失败: {str(e)}")

class TokenizationWindow:
    def __init__(self, parent, content):
        self.master = parent
        self.content = content
        self.window = tk.Toplevel(parent)
        self.window.title('分词结果')
        self.window.geometry('1000x700')
        self.window.configure(bg='#f0f2f5')
        self.window.transient(parent)  # 设置为父窗口的临时窗口
        
        # 创建主框架
        main_frame = ttk.Frame(self.window, style='Main.TFrame')
        main_frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 创建标题标签
        title_frame = ttk.Frame(main_frame, style='Title.TFrame')
        title_frame.pack(fill='x', pady=(0, 15))
        
        title_label = ttk.Label(
            title_frame, 
            text='文本分词处理', 
            style='Title.TLabel'
        )
        title_label.pack(pady=5)
        
        # 创建内容框架
        content_frame = ttk.Frame(main_frame, style='Content.TFrame')
        content_frame.pack(fill='both', expand=True, pady=5)
        
        # 分词参数设置区域
        settings_frame = ttk.LabelFrame(
            content_frame, 
            text='分词设置', 
            style='Card.TLabelframe'
        )
        settings_frame.pack(fill='x', pady=(0, 10), ipady=5)
        
        # 分词模式选择
        mode_frame = ttk.Frame(settings_frame)
        mode_frame.pack(fill='x', padx=15, pady=5)
        
        mode_label = ttk.Label(mode_frame, text='分词模式:')
        mode_label.pack(side='left', padx=(0, 10))
        
        self.mode_var = tk.StringVar(value='精确模式')
        modes = ['精确模式', '全模式', '搜索引擎模式']
        mode_combo = ttk.Combobox(
            mode_frame, 
            textvariable=self.mode_var, 
            values=modes, 
            width=15,
            state='readonly'
        )
        mode_combo.pack(side='left', padx=5)
        mode_combo.bind('<<ComboboxSelected>>', self.update_tokenize)
        
        # 停用词处理
        self.stop_words_var = tk.BooleanVar(value=True)
        stop_words_check = ttk.Checkbutton(
            mode_frame, 
            text='使用停用词', 
            variable=self.stop_words_var,
            command=self.update_tokenize
        )
        stop_words_check.pack(side='left', padx=20)
        
        # 自定义词典
        self.custom_dict_var = tk.BooleanVar(value=False)
        custom_dict_check = ttk.Checkbutton(
            mode_frame, 
            text='使用自定义词典', 
            variable=self.custom_dict_var,
            command=self.update_tokenize
        )
        custom_dict_check.pack(side='left', padx=5)
        
        # 显示模式选择
        display_frame = ttk.Frame(settings_frame)
        display_frame.pack(fill='x', padx=15, pady=5)
        
        display_label = ttk.Label(display_frame, text='显示模式:')
        display_label.pack(side='left', padx=(0, 10))
        
        self.display_var = tk.StringVar(value='词间空格')
        displays = ['词间空格', '斜杠分隔', '词性标注']
        display_combo = ttk.Combobox(
            display_frame, 
            textvariable=self.display_var, 
            values=displays, 
            width=15,
            state='readonly'
        )
        display_combo.pack(side='left', padx=5)
        display_combo.bind('<<ComboboxSelected>>', self.update_display)
        
        # 主内容区
        paned_window = ttk.PanedWindow(content_frame, orient=tk.HORIZONTAL)
        paned_window.pack(fill='both', expand=True)
        
        # 左侧原文显示
        left_frame = ttk.LabelFrame(
            paned_window, 
            text='原文内容', 
            style='Card.TLabelframe'
        )
        
        self.orig_text = tk.Text(
            left_frame, 
            wrap=tk.WORD,
            font=('微软雅黑', 11),
            bg='#ffffff',
            fg='#333333',
            padx=12,
            pady=12,
            relief='flat'
        )
        orig_scroll = ttk.Scrollbar(left_frame, command=self.orig_text.yview)
        self.orig_text.configure(yscrollcommand=orig_scroll.set)
        
        # 右侧分词结果
        right_frame = ttk.LabelFrame(
            paned_window, 
            text='分词结果', 
            style='Card.TLabelframe'
        )
        
        self.token_text = tk.Text(
            right_frame, 
            wrap=tk.WORD,
            font=('微软雅黑', 11),
            bg='#ffffff',
            fg='#333333',
            padx=12,
            pady=12,
            relief='flat'
        )
        token_scroll = ttk.Scrollbar(right_frame, command=self.token_text.yview)
        self.token_text.configure(yscrollcommand=token_scroll.set)
        
        # 添加到窗格
        paned_window.add(left_frame, weight=1)
        paned_window.add(right_frame, weight=1)
        
        # 布局
        self.orig_text.pack(side='left', fill='both', expand=True)
        orig_scroll.pack(side='right', fill='y')
        
        self.token_text.pack(side='left', fill='both', expand=True)
        token_scroll.pack(side='right', fill='y')

        # 控制按钮
        btn_frame = ttk.Frame(main_frame)
        btn_frame.pack(pady=10)
        
        self.copy_btn = ttk.Button(
            btn_frame, 
            text='复制分词结果', 
            style='Accent.TButton',
            command=self.copy_result
        )
        self.copy_btn.pack(side='left', padx=5)
        
        self.save_btn = ttk.Button(
            btn_frame, 
            text='保存分词结果', 
            style='Upload.TButton',
            command=self.save_result
        )
        self.save_btn.pack(side='left', padx=5)
        
        self.close_btn = ttk.Button(
            btn_frame, 
            text='关闭', 
            command=self.window.destroy
        )
        self.close_btn.pack(side='left', padx=5)
        
        # 初始化内容
        self.orig_text.insert(tk.END, self.content)
        self.orig_text.config(state='disabled')  # 设为只读
        
        # 初始化停用词列表
        self.stop_words = self.load_stop_words()
        
        # 进行分词处理
        self.update_tokenize()
    
    def load_stop_words(self):
        """加载停用词表"""
        common_stop_words = [
            '的', '了', '在', '是', '我', '有', '和', '就', '不', '人', '都', '一', '一个', '上', '也', '很', '到', '说', '要',
            '去', '你', '会', '着', '没有', '看', '好', '自己', '这', '那', '这个', '那个', '他', '她', '它', '这些', '那些',
            '这样', '那样', '什么', '怎么', '如何', '为什么', '因为', '所以', '但是', '可是', '然而', '而且', '并且', '或者',
            '不过', '虽然', '如果', '既然', '无论', '尽管', '除非', '只要', '这么', '那么', '多么', '太', '非常', '十分', 
            '极其', '尤其', '特别', '更加', '如此', '一样', '一直', '曾经', '已经', '将要', '正在', '应该', '必须', '可能',
            '宁可', '宁愿', '不如', '不仅', '但', '且', '何', '能', '或', '者', '每', '以', '被', '比', '把', '所', '给',
            '跟', '向', '让', '得', '对', '过', '来', '做', '来着', '啊', '呢', '吧', '吗', '嘛', '呀', '哇', '哦', '喽',
            '啦', '呗', '着呢', '罢了', '而已', '等等'
        ]
        try:
            # 尝试从文件加载
            if os.path.exists('stop_words.txt'):
                with open('stop_words.txt', 'r', encoding='utf-8') as f:
                    stop_words_list = [line.strip() for line in f if line.strip()]
                    if stop_words_list:
                        return set(stop_words_list)
        except:
            pass
        
        # 返回默认停用词
        return set(common_stop_words)
    
    def update_tokenize(self, event=None):
        """更新分词结果"""
        mode = self.mode_var.get()
        
        # 根据模式选择分词方式
        if mode == '精确模式':
            words = jieba.lcut(self.content)
        elif mode == '全模式':
            words = jieba.lcut(self.content, cut_all=True)
        elif mode == '搜索引擎模式':
            words = jieba.lcut_for_search(self.content)
        
        # 处理停用词
        if self.stop_words_var.get():
            words = [word for word in words if word not in self.stop_words and len(word.strip()) > 0]
        
        # 使用自定义词典
        if self.custom_dict_var.get():
            # 检查自定义词典是否存在
            if os.path.exists('user_dict.txt'):
                jieba.load_userdict('user_dict.txt')
                # 重新分词
                if mode == '精确模式':
                    words = jieba.lcut(self.content)
                elif mode == '全模式':
                    words = jieba.lcut(self.content, cut_all=True)
                elif mode == '搜索引擎模式':
                    words = jieba.lcut_for_search(self.content)
                
                # 处理停用词
                if self.stop_words_var.get():
                    words = [word for word in words if word not in self.stop_words and len(word.strip()) > 0]
            else:
                messagebox.showinfo('提示', '未找到自定义词典文件（user_dict.txt），使用默认分词')
        
        # 根据显示模式格式化
        self.tokenized_words = words
        self.update_display()
    
    def update_display(self, event=None):
        """更新分词显示方式"""
        display_mode = self.display_var.get()
        
        if not hasattr(self, 'tokenized_words'):
            return
            
        self.token_text.config(state='normal')
        self.token_text.delete(1.0, tk.END)
        
        if display_mode == '词间空格':
            result = ' '.join(self.tokenized_words)
            self.token_text.insert(tk.END, result)
        elif display_mode == '斜杠分隔':
            result = '/'.join(self.tokenized_words)
            self.token_text.insert(tk.END, result)
        elif display_mode == '词性标注':
            import jieba.posseg as pseg
            words_with_tags = pseg.cut(self.content)
            
            # 格式化显示
            result = ''
            for word, flag in words_with_tags:
                # 如果启用停用词过滤，跳过停用词
                if self.stop_words_var.get() and word in self.stop_words:
                    continue
                result += f"{word}/{flag} "
            
            self.token_text.insert(tk.END, result)
        
        self.token_text.config(state='disabled')
        
        # 保存处理结果到历史记录
        try:
            display_content = self.token_text.get(1.0, tk.END)
            if hasattr(self.master, 'save_history'):
                self.master.save_history('分词处理', self.content, display_content)
        except Exception as e:
            print(f"保存分词历史记录失败: {e}")
    
    def copy_result(self):
        """复制分词结果到剪贴板"""
        result = self.token_text.get(1.0, tk.END)
        self.window.clipboard_clear()
        self.window.clipboard_append(result)
        messagebox.showinfo('提示', '分词结果已复制到剪贴板')
    
    def save_result(self):
        """保存分词结果到文件"""
        result = self.token_text.get(1.0, tk.END)
        file_path = filedialog.asksaveasfilename(
            defaultextension='.txt',
            filetypes=[('文本文件', '*.txt'), ('所有文件', '*.*')]
        )
        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(result)
                messagebox.showinfo('提示', f'分词结果已保存至: {file_path}')
            except Exception as e:
                messagebox.showerror('错误', f'保存失败: {str(e)}')

class WeightCalculationWindow:
    def __init__(self, parent, content):
        self.content = content
        self.master = parent
        self.window = tk.Toplevel(parent)
        self.window.title('权重计算')
        self.window.geometry('1000x700')
        self.window.configure(bg='#f0f2f5')
        self.window.transient(parent)  # 设置为父窗口的临时窗口
        
        # 创建主框架
        main_frame = ttk.Frame(self.window, style='Main.TFrame')
        main_frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 创建标题标签
        title_frame = ttk.Frame(main_frame, style='Title.TFrame')
        title_frame.pack(fill='x', pady=(0, 15))
        
        title_label = ttk.Label(
            title_frame, 
            text='文本权重计算', 
            style='Title.TLabel'
        )
        title_label.pack(pady=5)
        
        # 创建内容框架
        content_frame = ttk.Frame(main_frame, style='Content.TFrame')
        content_frame.pack(fill='both', expand=True, pady=5)
        
        # 算法选择区域
        settings_frame = ttk.LabelFrame(
            content_frame, 
            text='计算方法设置', 
            style='Card.TLabelframe'
        )
        settings_frame.pack(fill='x', pady=(0, 10), ipady=5)
        
        # 算法选择按钮
        algorithm_frame = ttk.Frame(settings_frame)
        algorithm_frame.pack(fill='x', padx=15, pady=10)
        
        self.algorithm_var = tk.StringVar(value='TF-IDF')
        
        # 使用更美观的单选按钮
        ttk.Label(algorithm_frame, text='选择算法:').pack(side='left', padx=(0, 10))
        
        tfidf_radio = ttk.Radiobutton(
            algorithm_frame, 
            text='TF-IDF', 
            variable=self.algorithm_var, 
            value='TF-IDF'
        )
        tfidf_radio.pack(side='left', padx=(0, 20))
        
        textrank_radio = ttk.Radiobutton(
            algorithm_frame, 
            text='TextRank', 
            variable=self.algorithm_var, 
            value='TextRank'
        )
        textrank_radio.pack(side='left', padx=(0, 20))
        
        lsa_radio = ttk.Radiobutton(
            algorithm_frame, 
            text='LSA', 
            variable=self.algorithm_var, 
            value='LSA'
        )
        lsa_radio.pack(side='left', padx=(0, 20))
        
        # 算法说明区域
        desc_frame = ttk.Frame(settings_frame)
        desc_frame.pack(fill='x', padx=15, pady=(0, 10))
        
        self.desc_text = tk.Text(
            desc_frame, 
            height=3, 
            wrap=tk.WORD, 
            font=('微软雅黑', 10),
            bg='#f8f9fa',
            fg='#6c757d',
            relief='flat',
            padx=10,
            pady=5
        )
        self.desc_text.pack(fill='x')
        self.desc_text.insert(tk.END, self.get_algorithm_description('TF-IDF'))
        self.desc_text.config(state='disabled')
        
        # 监听算法变化
        self.algorithm_var.trace_add('write', self.update_algorithm_description)
        
        # 参数设置框
        params_frame = ttk.LabelFrame(
            content_frame,
            text='参数设置',
            style='Card.TLabelframe'
        )
        params_frame.pack(fill='x', pady=(0, 10), ipady=5)
        
        # 不同算法的参数
        self.tfidf_frame = ttk.Frame(params_frame)
        
        # TF-IDF参数
        ttk.Label(self.tfidf_frame, text='最大特征数:').grid(row=0, column=0, padx=10, pady=5, sticky='w')
        
        self.max_features_var = tk.StringVar(value='100')
        max_features_entry = ttk.Entry(self.tfidf_frame, textvariable=self.max_features_var, width=10)
        max_features_entry.grid(row=0, column=1, padx=10, pady=5, sticky='w')
        
        ttk.Label(self.tfidf_frame, text='最小文档频率:').grid(row=0, column=2, padx=10, pady=5, sticky='w')
        
        self.min_df_var = tk.StringVar(value='1')
        min_df_entry = ttk.Entry(self.tfidf_frame, textvariable=self.min_df_var, width=10)
        min_df_entry.grid(row=0, column=3, padx=10, pady=5, sticky='w')
        
        # TextRank参数
        self.textrank_frame = ttk.Frame(params_frame)
        
        ttk.Label(self.textrank_frame, text='窗口大小:').grid(row=0, column=0, padx=10, pady=5, sticky='w')
        
        self.window_size_var = tk.StringVar(value='3')
        window_size_entry = ttk.Entry(self.textrank_frame, textvariable=self.window_size_var, width=10)
        window_size_entry.grid(row=0, column=1, padx=10, pady=5, sticky='w')
        
        ttk.Label(self.textrank_frame, text='迭代次数:').grid(row=0, column=2, padx=10, pady=5, sticky='w')
        
        self.iterations_var = tk.StringVar(value='10')
        iterations_entry = ttk.Entry(self.textrank_frame, textvariable=self.iterations_var, width=10)
        iterations_entry.grid(row=0, column=3, padx=10, pady=5, sticky='w')
        
        # LSA参数
        self.lsa_frame = ttk.Frame(params_frame)
        
        ttk.Label(self.lsa_frame, text='主题数量:').grid(row=0, column=0, padx=10, pady=5, sticky='w')
        
        self.n_components_var = tk.StringVar(value='5')
        n_components_entry = ttk.Entry(self.lsa_frame, textvariable=self.n_components_var, width=10)
        n_components_entry.grid(row=0, column=1, padx=10, pady=5, sticky='w')
        
        # 根据当前选择显示参数
        self.update_params_frame()
        
        # 监听算法变化更新参数面板
        self.algorithm_var.trace_add('write', self.update_params_frame)
        
        # 结果显示区域
        result_frame = ttk.LabelFrame(
            content_frame, 
            text='计算结果', 
            style='Card.TLabelframe'
        )
        result_frame.pack(fill='both', expand=True)
        
        # 添加计算按钮到结果框架顶部
        calc_btn_frame = ttk.Frame(result_frame)
        calc_btn_frame.pack(fill='x', padx=10, pady=(5, 0))
        
        self.calculate_btn = ttk.Button(
            calc_btn_frame, 
            text='开始计算', 
            style='Accent.TButton',
            command=self.start_calculation
        )
        self.calculate_btn.pack(side='left', padx=5)
        
        # 结果文本区域
        result_container = ttk.Frame(result_frame)
        result_container.pack(fill='both', expand=True, padx=10, pady=10)
        
        self.result_text = tk.Text(
            result_container, 
            wrap=tk.WORD,
            font=('微软雅黑', 11),
            bg='#ffffff',
            fg='#333333',
            relief='flat'
        )
        result_scroll = ttk.Scrollbar(result_container, command=self.result_text.yview)
        self.result_text.configure(yscrollcommand=result_scroll.set)
        
        self.result_text.pack(side='left', fill='both', expand=True)
        result_scroll.pack(side='right', fill='y')
        
        # 底部按钮框架
        btn_frame = ttk.Frame(main_frame)
        btn_frame.pack(pady=10)
        
        self.copy_btn = ttk.Button(
            btn_frame, 
            text='复制结果', 
            style='Upload.TButton',
            command=self.copy_result,
            state='disabled'
        )
        self.copy_btn.pack(side='left', padx=5)
        
        self.save_btn = ttk.Button(
            btn_frame, 
            text='保存结果', 
            style='Upload.TButton',
            command=self.save_result,
            state='disabled'
        )
        self.save_btn.pack(side='left', padx=5)
        
        self.close_btn = ttk.Button(
            btn_frame, 
            text='关闭', 
            command=self.window.destroy
        )
        self.close_btn.pack(side='left', padx=5)
    
    def get_algorithm_description(self, algorithm):
        """获取算法描述"""
        descriptions = {
            'TF-IDF': 'TF-IDF（词频-逆文档频率）是一种统计方法，用于评估一个词对于文档集或语料库中一个文档的重要程度。TF-IDF值越大，表明该词在这个文档中的重要性越高。',
            'TextRank': 'TextRank是一种基于图的排序算法，类似于谷歌的PageRank。它通过构建词汇共现图，计算每个词的重要性。TextRank特别适合于发现文本中的关键词和关键短语。',
            'LSA': 'LSA（潜在语义分析）是一种通过奇异值分解（SVD）来发现词与文档之间隐含关系的技术。LSA可以捕获文本的语义结构，有助于识别文本的主题和关键概念。'
        }
        return descriptions.get(algorithm, '')
    
    def update_algorithm_description(self, *args):
        """更新算法描述"""
        algorithm = self.algorithm_var.get()
        description = self.get_algorithm_description(algorithm)
        
        self.desc_text.config(state='normal')
        self.desc_text.delete(1.0, tk.END)
        self.desc_text.insert(tk.END, description)
        self.desc_text.config(state='disabled')
    
    def update_params_frame(self, *args):
        """根据所选算法更新参数面板"""
        algorithm = self.algorithm_var.get()
        
        # 先隐藏所有参数框
        for frame in [self.tfidf_frame, self.textrank_frame, self.lsa_frame]:
            frame.pack_forget()
        
        # 根据算法显示对应参数框
        if algorithm == 'TF-IDF':
            self.tfidf_frame.pack(fill='x', padx=10, pady=10)
        elif algorithm == 'TextRank':
            self.textrank_frame.pack(fill='x', padx=10, pady=10)
        elif algorithm == 'LSA':
            self.lsa_frame.pack(fill='x', padx=10, pady=10)
    
    def start_calculation(self):
        """开始计算权重"""
        content = self.content
        if not content.strip():
            messagebox.showwarning('警告', '文档内容为空')
            return
    
        algorithm = self.algorithm_var.get()
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, f"正在计算中，请稍候...\n\n算法: {algorithm}")
        self.window.update()
        
        try:
            # 根据算法选择不同的计算方法
            if algorithm == 'TF-IDF':
                max_features = int(self.max_features_var.get())
                min_df = int(self.min_df_var.get())
                result = self.calculate_tfidf(content, max_features, min_df)
            elif algorithm == 'TextRank':
                window_size = int(self.window_size_var.get())
                iterations = int(self.iterations_var.get())
                result = self.calculate_textrank(content, window_size, iterations)
            elif algorithm == 'LSA':
                n_components = int(self.n_components_var.get())
                result = self.calculate_lsa(content, n_components)
            else:
                raise ValueError('未知算法')
        
            # 显示结果
            self.result_text.delete(1.0, tk.END)
            self.result_text.insert(tk.END, result)
            
            # 激活按钮
            self.copy_btn.config(state='normal')
            self.save_btn.config(state='normal')
            
            # 保存计算结果到历史记录
            if hasattr(self.master, 'save_history'):
                self.master.save_history(
                    operation=f'{algorithm}权重计算',
                    content=content,
                    result=result
                )
                
            # 更新状态
            if hasattr(self.master, 'update_status'):
                self.master.update_status(f"{algorithm}权重计算完成")
                
        except Exception as e:
            error_msg = f'计算错误: {str(e)}\n请检查输入参数是否正确'
            self.result_text.delete(1.0, tk.END)
            self.result_text.insert(tk.END, error_msg)
            messagebox.showerror('计算错误', error_msg)
            print(f"计算错误详情: {str(e)}")
            traceback.print_exc()
            
            if hasattr(self.master, 'update_status'):
                self.master.update_status(f"权重计算失败: {str(e)}")
    
    def calculate_tfidf(self, text, max_features=100, min_df=1):
        """TF-IDF权重计算"""
        # 分词
        words = ' '.join(jieba.cut(text))
        sentences = [words]  # 将整个文本作为一个文档
        
        # 创建TF-IDF向量化器
        vectorizer = TfidfVectorizer(max_features=max_features, min_df=min_df)
        tfidf_matrix = vectorizer.fit_transform(sentences)
        feature_names = vectorizer.get_feature_names_out()
        
        # 获取每个词的TF-IDF分数
        features = []
        for col in range(tfidf_matrix.shape[1]):
            features.append((feature_names[col], tfidf_matrix[0, col]))
        
        # 按分数降序排序
        sorted_features = sorted(features, key=lambda x: x[1], reverse=True)
        
        # 格式化显示结果
        result = "## TF-IDF权重计算结果\n\n"
        result += f"总词汇量: {len(sorted_features)}\n"
        result += f"最大特征数: {max_features}, 最小文档频率: {min_df}\n\n"
        result += "### 权重最高的词汇:\n\n"
        result += "{:<15} {:<10}\n".format("词汇", "权重")
        result += "-" * 25 + "\n"
        
        for word, score in sorted_features[:50]:  # 显示前50个
            result += "{:<15} {:.6f}\n".format(word, score)
            
        return result
    
    def calculate_textrank(self, text, window_size=3, iterations=10):
        """TextRank权重计算"""
        # 分词
        words = list(jieba.cut(text))
        
        # 建立词图
        graph = {}
        for i in range(len(words)):
            if words[i] not in graph:
                graph[words[i]] = {}
                
            # 在窗口内建立连接
            for j in range(i+1, min(i+window_size+1, len(words))):
                if words[j] not in graph:
                    graph[words[j]] = {}
                
                # 增加共现权重
                graph[words[i]][words[j]] = graph[words[i]].get(words[j], 0) + 1
                graph[words[j]][words[i]] = graph[words[j]].get(words[i], 0) + 1
        
        # TextRank迭代计算
        damping = 0.85  # 阻尼系数
        min_diff = 0.00001  # 最小变化阈值
        
        # 初始化分数
        scores = {word: 1.0 for word in graph}
        
        # 迭代
        for _ in range(iterations):
            prev_scores = scores.copy()
            
            # 更新所有词的分数
            for word in graph:
                score = 1 - damping  # 基础分数
                
                # 计算邻接词的贡献
                for linked_word, weight in graph[word].items():
                    # 计算邻接词的贡献值
                    if linked_word in prev_scores:
                        total_weight = sum(graph[linked_word].values())
                        if total_weight > 0:
                            contribution = weight / total_weight * prev_scores[linked_word]
                            score += damping * contribution
                
                scores[word] = score
                
            # 检查是否收敛
            diff = sum(abs(scores[word] - prev_scores[word]) for word in scores)
            if diff < min_diff:
                break
        
        # 归一化分数
        max_score = max(scores.values()) if scores else 1.0
        normalized_scores = {word: score/max_score for word, score in scores.items()}
        
        # 按分数降序排序
        sorted_words = sorted(normalized_scores.items(), key=lambda x: x[1], reverse=True)
        
        # 格式化显示结果
        result = "## TextRank权重计算结果\n\n"
        result += f"总词汇量: {len(sorted_words)}\n"
        result += f"窗口大小: {window_size}, 迭代次数: {iterations}\n\n"
        result += "### 权重最高的词汇:\n\n"
        result += "{:<15} {:<10}\n".format("词汇", "权重")
        result += "-" * 25 + "\n"
        
        for word, score in sorted_words[:50]:  # 显示前50个
            result += "{:<15} {:.6f}\n".format(word, score)
            
        return result
    
    def calculate_lsa(self, text, n_components=5):
        """LSA (潜在语义分析) 权重计算"""
        # 分词
        sentences = [s.strip() for s in re.split(r'[。！？.!?]', text) if s.strip()]
        
        # 如果文本太短，无法进行有效分析
        if len(sentences) < 3:
            return "文本太短，无法进行有效的LSA分析。请提供更多文本内容。"
        
        # 创建文档-词汇矩阵
        vectorizer = TfidfVectorizer()
        try:
            X = vectorizer.fit_transform([' '.join(jieba.cut(s)) for s in sentences])
        except ValueError as e:
            return f"矩阵构建失败: {str(e)}\n请尝试提供更多文本内容。"
            
        # 确保n_components不超过矩阵的最小维度
        n_components = min(n_components, min(X.shape[0], X.shape[1]) - 1, 20)
        if n_components < 1:
            return "文本特征数量太少，无法进行SVD分解。请提供更多文本内容。"
        
        # 进行SVD分解
        try:
            U, sigma, VT = randomized_svd(X, n_components=n_components, random_state=42)
        except Exception as e:
            return f"SVD分解失败: {str(e)}\n请尝试减少主题数量或提供更多文本内容。"
            
        # 获取特征词
        terms = vectorizer.get_feature_names_out()
        
        # 格式化结果
        result = "## LSA (潜在语义分析) 结果\n\n"
        result += f"文档数: {len(sentences)}, 词汇量: {len(terms)}\n"
        result += f"主题数量: {n_components}\n\n"
        
        # 展示每个主题的关键词
        for i, topic in enumerate(VT):
            sorted_indices = topic.argsort()[::-1][:10]  # 每个主题取前10个词
            
            result += f"### 主题 {i+1}:\n\n"
            result += "{:<15} {:<10}\n".format("词汇", "权重")
            result += "-" * 25 + "\n"
            
            for idx in sorted_indices:
                result += "{:<15} {:.6f}\n".format(terms[idx], topic[idx])
            
            result += "\n"
        
        return result
        
    def copy_result(self):
        """复制计算结果到剪贴板"""
        result = self.result_text.get(1.0, tk.END)
        self.window.clipboard_clear()
        self.window.clipboard_append(result)
        messagebox.showinfo('提示', '计算结果已复制到剪贴板')
    
    def save_result(self):
        """保存计算结果到文件"""
        result = self.result_text.get(1.0, tk.END)
        file_path = filedialog.asksaveasfilename(
            defaultextension='.txt',
            filetypes=[('文本文件', '*.txt'), ('Markdown文件', '*.md'), ('所有文件', '*.*')]
        )
        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(result)
                messagebox.showinfo('提示', f'计算结果已保存至: {file_path}')
            except Exception as e:
                messagebox.showerror('错误', f'保存失败: {str(e)}')

class SummaryWindow:
    def __init__(self, parent, content):
        self.master = parent
        self.original_content = content
        self.window = tk.Toplevel(parent)
        self.window.title('文档摘要')
        self.window.geometry('1000x700')
        self.window.configure(bg='#f0f2f5')
        self.window.transient(parent)  # 设置为父窗口的临时窗口
        
        # 创建主框架
        main_frame = ttk.Frame(self.window, style='Main.TFrame')
        main_frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 创建标题标签
        title_frame = ttk.Frame(main_frame, style='Title.TFrame')
        title_frame.pack(fill='x', pady=(0, 15))
        
        title_label = ttk.Label(
            title_frame, 
            text='自动摘要生成', 
            style='Title.TLabel'
        )
        title_label.pack(pady=5)
        
        # 创建内容框架
        content_frame = ttk.Frame(main_frame, style='Content.TFrame')
        content_frame.pack(fill='both', expand=True, pady=5)
        
        # 控制面板
        control_frame = ttk.LabelFrame(
            content_frame, 
            text='摘要设置', 
            style='Card.TLabelframe'
        )
        control_frame.pack(fill='x', pady=(0, 10), ipady=5)
        
        # 摘要长度设置
        length_frame = ttk.Frame(control_frame)
        length_frame.pack(fill='x', padx=15, pady=5)
        
        self.length_label = ttk.Label(length_frame, text='摘要长度:')
        self.length_label.pack(side='left', padx=(0, 10))
        
        self.length_scale = ttk.Scale(
            length_frame, 
            from_=100, 
            to=1000, 
            orient='horizontal',
            length=350,
            command=self.update_length_label
        )
        self.length_scale.pack(side='left')
        
        self.length_var = ttk.Label(length_frame, text='300字')
        self.length_var.pack(side='left', padx=10)
        
        # 算法设置
        algorithm_frame = ttk.Frame(control_frame)
        algorithm_frame.pack(fill='x', padx=15, pady=5)
        
        ttk.Label(algorithm_frame, text='摘要算法:').pack(side='left', padx=(0, 10))
        
        self.algorithm_var = tk.StringVar(value='LSA + TextRank')
        algorithms = ['LSA + TextRank', '仅TextRank', '仅LSA', '增强LSA']
        algorithm_combo = ttk.Combobox(
            algorithm_frame, 
            textvariable=self.algorithm_var,
            values=algorithms,
            width=15,
            state='readonly'
        )
        algorithm_combo.pack(side='left', padx=5)
        
        # 主题数量设置
        ttk.Label(algorithm_frame, text='主题数量:').pack(side='left', padx=(20, 10))
        self.topic_var = tk.StringVar(value='5')
        topic_spin = ttk.Spinbox(
            algorithm_frame,
            from_=2,
            to=10,
            textvariable=self.topic_var,
            width=5
        )
        topic_spin.pack(side='left', padx=5)
        
        # 优化设置
        optimize_frame = ttk.Frame(control_frame)
        optimize_frame.pack(fill='x', padx=15, pady=5)
        
        self.optimize_var = tk.BooleanVar(value=True)
        optimize_check = ttk.Checkbutton(
            optimize_frame, 
            text='优化连贯性', 
            variable=self.optimize_var
        )
        optimize_check.pack(side='left', padx=(0, 20))
        
        self.deduplicate_var = tk.BooleanVar(value=True)
        deduplicate_check = ttk.Checkbutton(
            optimize_frame, 
            text='去除冗余', 
            variable=self.deduplicate_var
        )
        deduplicate_check.pack(side='left', padx=(0, 20))
        
        self.keyword_highlight_var = tk.BooleanVar(value=True)
        keyword_highlight_check = ttk.Checkbutton(
            optimize_frame, 
            text='关键词突出显示', 
            variable=self.keyword_highlight_var
        )
        keyword_highlight_check.pack(side='left')
        
        # 重新生成按钮
        self.regenerate_btn = ttk.Button(
            control_frame, 
            text='重新生成',
            style='Accent.TButton', 
            command=self.regenerate_summary
        )
        self.regenerate_btn.pack(side='right', padx=15, pady=5)
        
        # 摘要显示区域
        paned_window = ttk.PanedWindow(content_frame, orient=tk.HORIZONTAL)
        paned_window.pack(fill='both', expand=True)
        
        # 左侧原文显示
        left_frame = ttk.LabelFrame(
            paned_window, 
            text='原文内容', 
            style='Card.TLabelframe'
        )
        
        self.orig_text = tk.Text(
            left_frame, 
            wrap=tk.WORD,
            font=('微软雅黑', 11),
            bg='#ffffff',
            fg='#333333',
            padx=12,
            pady=12,
            relief='flat'
        )
        orig_scroll = ttk.Scrollbar(left_frame, command=self.orig_text.yview)
        self.orig_text.configure(yscrollcommand=orig_scroll.set)
        
        # 右侧摘要结果
        right_frame = ttk.LabelFrame(
            paned_window, 
            text='摘要结果', 
            style='Card.TLabelframe'
        )
        
        self.summary_text = tk.Text(
            right_frame, 
            wrap=tk.WORD,
            font=('微软雅黑', 11),
            bg='#ffffff',
            fg='#333333',
            padx=12,
            pady=12,
            relief='flat'
        )
        summary_scroll = ttk.Scrollbar(right_frame, command=self.summary_text.yview)
        self.summary_text.configure(yscrollcommand=summary_scroll.set)
        
        # 添加到窗格
        paned_window.add(left_frame, weight=1)
        paned_window.add(right_frame, weight=1)
        
        # 布局
        self.orig_text.pack(side='left', fill='both', expand=True)
        orig_scroll.pack(side='right', fill='y')
        
        self.summary_text.pack(side='left', fill='both', expand=True)
        summary_scroll.pack(side='right', fill='y')
        
        # 状态框
        status_frame = ttk.Frame(content_frame)
        status_frame.pack(fill='x', pady=(10, 5))
        
        self.status_var = tk.StringVar(value='准备生成摘要...')
        self.status_label = ttk.Label(
            status_frame, 
            textvariable=self.status_var,
            foreground='#6c757d',
            font=('微软雅黑', 9)
        )
        self.status_label.pack(side='left', padx=5)
        
        # 评估信息
        self.eval_var = tk.StringVar()
        eval_label = ttk.Label(
            status_frame,
            textvariable=self.eval_var,
            foreground='#28a745',
            font=('微软雅黑', 9, 'bold')
        )
        eval_label.pack(side='right', padx=5)
        
        # 操作按钮
        btn_frame = ttk.Frame(main_frame)
        btn_frame.pack(pady=10)
        
        self.copy_btn = ttk.Button(
            btn_frame, 
            text='复制摘要',
            style='Upload.TButton', 
            command=self.copy_summary
        )
        self.copy_btn.pack(side='left', padx=5)
        
        self.save_btn = ttk.Button(
            btn_frame, 
            text='保存文档',
            style='Upload.TButton', 
            command=self.save_summary
        )
        self.save_btn.pack(side='left', padx=5)
        
        self.extract_keywords_btn = ttk.Button(
            btn_frame,
            text='提取关键词',
            style='Upload.TButton',
            command=self.extract_keywords
        )
        self.extract_keywords_btn.pack(side='left', padx=5)
        
        self.close_btn = ttk.Button(
            btn_frame, 
            text='关闭', 
            command=self.window.destroy
        )
        self.close_btn.pack(side='left', padx=5)
        
        # 初始化内容
        self.orig_text.insert(tk.END, self.original_content)
        self.orig_text.config(state='disabled')  # 设为只读
        
        # 设置默认长度
        self.length_scale.set(300)
        
        # 关键词列表
        self.keywords = []
        
        # 初始化生成摘要
        self.generate_summary()
    
    def update_length_label(self, value):
        """更新摘要长度标签"""
        value = int(float(value))
        self.length_var.config(text=f'{value}字')
    
    def sentence_similarity(self, s1, s2):
        """计算句子相似度"""
        # 基于Jaccard相似度计算
        words1 = set(jieba.lcut(s1))
        words2 = set(jieba.lcut(s2))
        intersection = words1 & words2
        union = words1 | words2
        return len(intersection) / len(union) if union else 0
    
    def calculate_textrank(self, sentences):
        """计算句子TextRank得分"""
        # 构建相似度矩阵
        similarity_matrix = np.zeros((len(sentences), len(sentences)))
        for i in range(len(sentences)):
            for j in range(len(sentences)):
                if i != j:
                    similarity_matrix[i][j] = self.sentence_similarity(
                        sentences[i], sentences[j]
                    )
        
        # 迭代计算TextRank得分
        scores = np.ones(len(sentences))
        damping = 0.85
        for _ in range(20):
            new_scores = np.copy(scores)
            for i in range(len(sentences)):
                incoming = similarity_matrix[:,i]
                new_scores[i] = (1 - damping) + damping * np.sum(incoming * scores)
            scores = new_scores
        return scores

    def optimize_coherence(self, sentences, indices):
        """优化摘要连贯性"""
        if not self.optimize_var.get():
            return [sentences[i] for i in indices]
        
        # 重新按原文顺序排列句子
        ordered_sentences = []
        for i in range(len(sentences)):
            if i in indices:
                ordered_sentences.append(sentences[i])
        
        return ordered_sentences
    
    def extract_keywords(self):
        """提取文本关键词"""
        if not hasattr(self, 'summary'):
            messagebox.showinfo('提示', '请先生成摘要')
            return
            
        try:
            # 使用TF-IDF提取关键词
            words = ' '.join(jieba.cut(self.original_content))
            sentences = [words]
            vectorizer = TfidfVectorizer(max_features=20)
            tfidf_matrix = vectorizer.fit_transform(sentences)
            feature_names = vectorizer.get_feature_names_out()
            
            # 获取关键词及其权重
            features = []
            for col in range(tfidf_matrix.shape[1]):
                features.append((feature_names[col], tfidf_matrix[0, col]))
            
            # 按分数降序排序
            sorted_features = sorted(features, key=lambda x: x[1], reverse=True)
            
            # 格式化显示
            result = "文档关键词 (TF-IDF):\n\n"
            self.keywords = []
            for i, (word, score) in enumerate(sorted_features[:10]):
                result += f"{i+1}. {word}: {score:.4f}\n"
                self.keywords.append(word)
            
            # 显示结果
            messagebox.showinfo('关键词提取结果', result)
            
            # 如果勾选了关键词突出显示，则标记关键词
            if self.keyword_highlight_var.get() and self.keywords:
                self.highlight_keywords()
                
        except Exception as e:
            messagebox.showerror('错误', f'关键词提取失败: {str(e)}')
    
    def highlight_keywords(self):
        """在摘要中突出显示关键词"""
        if not hasattr(self, 'summary') or not self.keywords:
            return
            
        # 保存摘要内容
        summary_content = self.summary_text.get(1.0, tk.END)
        self.summary_text.config(state='normal')
        self.summary_text.delete(1.0, tk.END)
        self.summary_text.insert(tk.END, summary_content)
        
        # 设置高亮标签
        self.summary_text.tag_configure('highlight', background='#ffff99', foreground='#000000', font=('微软雅黑', 11, 'bold'))
        
        # 标记关键词
        for keyword in self.keywords:
            start_pos = '1.0'
            while True:
                start_pos = self.summary_text.search(keyword, start_pos, tk.END)
                if not start_pos:
                    break
                end_pos = f"{start_pos}+{len(keyword)}c"
                self.summary_text.tag_add('highlight', start_pos, end_pos)
                start_pos = end_pos
    
    def evaluate_summary(self, original, summary):
        """评估摘要质量"""
        if not summary:
            return 0, "无法评估"
            
        # 基于覆盖率和信息密度的简单评估
        orig_words = set(jieba.lcut(original))
        summ_words = set(jieba.lcut(summary))
        
        # 计算覆盖率
        coverage = len(summ_words.intersection(orig_words)) / len(orig_words) if orig_words else 0
        
        # 计算信息密度 (非停用词比例)
        common_stopwords = {'的', '了', '在', '是', '我', '有', '和', '就', '不', '人', '都', '一', '上', '也'}
        info_density = len([w for w in summ_words if w not in common_stopwords]) / len(summ_words) if summ_words else 0
        
        # 计算综合得分 (0-100)
        score = int((coverage * 0.6 + info_density * 0.4) * 100)
        
        # 评级
        if score >= 80:
            rating = "优"
        elif score >= 60:
            rating = "良"
        elif score >= 40:
            rating = "中"
        else:
            rating = "差"
            
        return score, rating

    def generate_summary(self):
        """生成摘要"""
        self.status_var.set('正在生成摘要...')
        self.window.update()
        
        algorithm = self.algorithm_var.get()
        target_length = int(self.length_scale.get())
        
        # 分割句子
        sentences = [s.strip() for s in re.split(r'[。！？!?.]', self.original_content) if s.strip()]
        
        # 检查文本长度
        if len(sentences) < 3:
            self.summary_text.delete(1.0, tk.END)
            self.summary_text.insert(tk.END, "文本太短，无法生成有效摘要。请提供更多文本内容(至少3个句子)。")
            self.status_var.set('文本太短，无法生成摘要')
            return
        
        try:
            # 创建词袋模型
            vectorizer = TfidfVectorizer(tokenizer=jieba.cut, stop_words=['的','了','是','在'])
            X = vectorizer.fit_transform(sentences)
            
            # 句子分数
            sentence_scores = {}
            
            # 根据选择的算法计算分数
            if algorithm in ['LSA + TextRank', '仅LSA', '增强LSA']:
                # 动态调整n_components
                try:
                    n_components = int(self.topic_var.get())
                except:
                    n_components = 5
                    
                max_components = min(X.shape[0], X.shape[1], 20) - 1
                n_components = min(max(2, n_components, max_components // 2), max_components)
                
                # SVD分解
                U, sigma, VT = randomized_svd(X, n_components=n_components, random_state=42)
                
                # 计算LSA分数
                lsa_scores = np.sum(np.square(U * sigma), axis=1)
                sentence_scores.update({i: lsa_scores[i] for i in range(len(sentences))})
                
                # 增强LSA: 考虑句子位置因素
                if algorithm == '增强LSA':
                    # 对于开头和结尾的句子增加权重
                    for i in range(min(3, len(sentences))):  # 开头3句
                        if i in sentence_scores:
                            sentence_scores[i] *= 1.2
                    
                    for i in range(max(0, len(sentences)-3), len(sentences)):  # 结尾3句
                        if i in sentence_scores:
                            sentence_scores[i] *= 1.1
            
            if algorithm in ['LSA + TextRank', '仅TextRank']:
                # 计算TextRank分数
                textrank_scores = self.calculate_textrank(sentences)
                
                # 如果同时使用两种算法，则组合分数
                if algorithm == 'LSA + TextRank':
                    for i in range(len(sentences)):
                        sentence_scores[i] = 0.6 * sentence_scores.get(i, 0) + 0.4 * textrank_scores[i]
                else:
                    sentence_scores.update({i: textrank_scores[i] for i in range(len(sentences))})
            
            # 按分数排序
            ranked_sentences = sorted(sentence_scores.items(), key=lambda x: x[1], reverse=True)
            
            # 选择句子策略
            selected_indices = []
            current_length = 0
            used_indices = set()
            
            # 去重阈值
            similarity_threshold = 0.7 if self.deduplicate_var.get() else 1.0
            
            # 处理每个句子
            for idx, _ in ranked_sentences:
                if idx in used_indices:
                    continue
                
                sentence = sentences[idx]
                sentence_length = len(sentence)
                
                # 长度检查
                if current_length + sentence_length > target_length * 1.2:
                    continue
                
                # 冗余检查
                is_redundant = False
                if self.deduplicate_var.get():
                    for sel_idx in selected_indices:
                        if self.sentence_similarity(sentence, sentences[sel_idx]) > similarity_threshold:
                            is_redundant = True
                            break
                if is_redundant:
                    continue
                
                selected_indices.append(idx)
                current_length += sentence_length
                used_indices.add(idx)
                
                # 达到目标长度
                if current_length >= target_length:
                    break
            
            # 优化连贯性：重新按原文顺序排列句子
            optimized_sentences = self.optimize_coherence(sentences, selected_indices)
            
            # 生成最终摘要
            self.summary = '。'.join(optimized_sentences) + '。'
            
            # 显示结果
            self.summary_text.config(state='normal')
            self.summary_text.delete(1.0, tk.END)
            self.summary_text.insert(tk.END, self.summary)
            self.summary_text.config(state='disabled')
            
            # 提取关键词
            self.extract_keywords()
            
            # 评估摘要质量
            score, rating = self.evaluate_summary(self.original_content, self.summary)
            self.eval_var.set(f"摘要质量评分: {score}/100 ({rating})")
            
            # 更新状态
            self.status_var.set(f'摘要生成完成 - 长度: {len(self.summary)}字, 选择了{len(selected_indices)}个句子')
            
        except Exception as e:
            error_msg = f"摘要生成失败: {str(e)}"
            self.summary_text.delete(1.0, tk.END)
            self.summary_text.insert(tk.END, error_msg)
            self.status_var.set('摘要生成失败')
            print(f"摘要生成错误: {e}")
            traceback.print_exc()
    
    def regenerate_summary(self):
        """重新生成摘要"""
        self.generate_summary()
    
    def copy_summary(self):
        """复制摘要到剪贴板"""
        if hasattr(self, 'summary'):
            self.window.clipboard_clear()
            self.window.clipboard_append(self.summary)
            self.status_var.set('摘要已复制到剪贴板')
            messagebox.showinfo('提示', '摘要已复制到剪贴板')
    
    def save_summary(self):
        """保存摘要到文件"""
        if not hasattr(self, 'summary'):
            return
            
        filepath = filedialog.asksaveasfilename(
            defaultextension='.txt',
            filetypes=[('文本文件', '*.txt'), ('Word文档', '*.docx'), ('所有文件', '*.*')]
        )
        if filepath:
            try:
                if filepath.endswith('.docx'):
                    doc = Document()
                    doc.add_paragraph(self.summary)
                    doc.save(filepath)
                else:
                    with open(filepath, 'w', encoding='utf-8') as f:
                        f.write(self.summary)
                self.status_var.set(f'摘要已保存至: {filepath}')
                messagebox.showinfo('保存成功', f'摘要已保存至：{filepath}')
            except Exception as e:
                messagebox.showerror('保存失败', f'保存文件时出错: {str(e)}')

class HistoryWindow:
    def __init__(self, parent):
        self.window = tk.Toplevel(parent)
        self.window.title('历史记录')
        self.window.geometry('800x600')

        # 历史记录列表
        self.tree = ttk.Treeview(self.window, columns=('timestamp', 'operation', 'preview'), show='headings')
        self.tree.heading('timestamp', text='时间')
        self.tree.heading('operation', text='操作类型')
        self.tree.heading('preview', text='内容预览')
        self.tree.column('timestamp', width=120)
        self.tree.column('operation', width=100)
        self.tree.column('preview', width=480)

        # 操作按钮
        self.btn_frame = ttk.Frame(self.window)
        self.view_btn = ttk.Button(self.btn_frame, text='查看详情', command=self.view_details)
        self.delete_btn = ttk.Button(self.btn_frame, text='删除记录', command=self.delete_record)
        self.clear_btn = ttk.Button(self.btn_frame, text='清空历史', command=self.clear_history)

        # 加载数据
        self.load_history()

        # 布局
        self.tree.pack(fill='both', expand=True, padx=10, pady=10)
        self.btn_frame.pack(pady=10)
        self.view_btn.pack(side='left', padx=5)
        self.delete_btn.pack(side='left', padx=5)
        self.clear_btn.pack(side='right', padx=5)

    def load_history(self):
        try:
            with open('history.json', 'r', encoding='utf-8') as f:
                history = json.load(f)
                for item in history:
                    self.tree.insert('', 'end', values=(item['timestamp'], item['operation'], item['original']))
        except (FileNotFoundError, json.JSONDecodeError):
            pass

    def view_details(self):
        selected = self.tree.selection()
        if not selected:
            return
        item_id = selected[0]
        values = self.tree.item(item_id, 'values')
        timestamp = values[0]
        operation = values[1]
        original_preview = values[2]

        try:
            with open('history.json', 'r', encoding='utf-8') as f:
                history = json.load(f)
                record = next(r for r in history if r['timestamp'] == timestamp and r['operation'] == operation and r['original'].startswith(original_preview))
                DetailWindow(self.window, record['original'], record['result'], record['operation'])
        except (StopIteration, FileNotFoundError):
            messagebox.showerror('错误', '找不到对应的历史记录')

    def delete_record(self):
        selected = self.tree.selection()
        if not selected:
            return
        item_id = selected[0]
        values = self.tree.item(item_id, 'values')
        timestamp = values[0]
        original_preview = values[1]

        try:
            with open('history.json', 'r+', encoding='utf-8') as f:
                history = json.load(f)
                history = [r for r in history if not (r['timestamp'] == timestamp and r['original'].startswith(original_preview))]
                f.seek(0)
                f.truncate()
                json.dump(history, f, ensure_ascii=False, indent=2)
            self.tree.delete(item_id)
            self.tree.update()
        except (FileNotFoundError, json.JSONDecodeError):
            messagebox.showerror('错误', '删除记录失败')

    def clear_history(self):
        if messagebox.askyesno('确认', '确定要清空所有历史记录吗？'):
            try:
                with open('history.json', 'w') as f:
                    f.write('[]')
                for item in self.tree.get_children():
                    self.tree.delete(item)
            except FileNotFoundError:
                pass

class DetailWindow:
    def __init__(self, parent, original, summary, operation):
        self.window = tk.Toplevel(parent)
        self.operation = operation
        self.window.title('历史记录详情')
        self.window.geometry('900x600')

        # 创建Notebook
        self.notebook = ttk.Notebook(self.window)

        # 原文标签页
        self.original_frame = ttk.Frame(self.notebook)
        self.original_text = tk.Text(self.original_frame, wrap=tk.WORD)
        self.original_text.insert(tk.END, original)
        self.original_text.config(state='disabled')

        # 摘要标签页
        self.summary_frame = ttk.Frame(self.notebook)
        self.summary_text = tk.Text(self.summary_frame, wrap=tk.WORD)
        self.summary_text.insert(tk.END, summary)
        self.summary_text.config(state='disabled')

        # 布局
        self.original_text.pack(fill='both', expand=True)
        self.summary_text.pack(fill='both', expand=True)
        self.notebook.add(self.original_frame, text='原文内容')
        self.notebook.add(self.summary_frame, text=f'{self.operation}结果')
        self.notebook.pack(fill='both', expand=True, padx=10, pady=10)

if __name__ == '__main__':
    app = MainWindow()
    app.mainloop()